﻿using Niknak.Services.ServiceCore;
using Niknak.Services.ServiceCore.Wcf;
using Niknak.Services.TaskScheduler;
using Niknak.Services.TaskScheduler.Interfaces.DataModel;
using Niknak.Services.TaskScheduler.UI.Web;
using Niknak.Services.TaskScheduler.Wcf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI.WebControls;

namespace Niknak.Services.TaskScheduler.UI.WebControls
{
    public class EventLog<ExceptionHandlerType, WcfConfigurationSettings, ScheduledTaskType, AuditLogType, AuditLogEntryType> : EmbeddedUserControl
        where ExceptionHandlerType : IExceptionHandler, new()
        where WcfConfigurationSettings : IWcfConfig, new()
        where ScheduledTaskType : IScheduledTask, new()
        where AuditLogType : IAuditLog<AuditLogEntryType>, new()
        where AuditLogEntryType : IAuditLogEntry
    {
        #region Controls
        protected global::System.Web.UI.WebControls.DropDownList uiDdlEventLog;
        protected global::System.Web.UI.WebControls.TextBox uiTxtSource;
        protected global::System.Web.UI.WebControls.CheckBoxList uiCbxLevel;
        protected global::System.Web.UI.WebControls.TextBox uiTxtAfterDate;
        protected global::System.Web.UI.WebControls.TextBox uiTxtBeforeDate;
        protected global::System.Web.UI.WebControls.Button uiBtnFind;
        protected global::System.Web.UI.HtmlControls.HtmlGenericControl uiDivPaging;
        protected global::System.Web.UI.WebControls.Repeater uiRptEvents;
        protected global::System.Web.UI.WebControls.Literal uiLitPrevPage;
        protected global::System.Web.UI.WebControls.Literal uiLitNextPage;
        #endregion

        private ScheduledTaskType ScheduledTask = new ScheduledTaskType();
        private AuditLogType AuditLogInstance = new AuditLogType();

        private string QsEventLogName
        {
            get { return Request.QueryString["log"]; }
        }

        private string QsSource
        {
            get { return Request.QueryString["source"]; }
        }

        private int[] _QsLevels = null;
        private int[] QsLevels
        {
            get
            {
                string rawLevels = Request.QueryString["levels"];
                if (_QsLevels == null && !string.IsNullOrEmpty(rawLevels))
                {
                    foreach (char chr in rawLevels)
                        if (!new char[] { ',', '1', '2', '3', '4' }.Contains(chr))
                            return null;

                    if (rawLevels.Contains(','))
                        _QsLevels = rawLevels.Split(',').Select(l => int.Parse(l)).ToArray();
                    else
                        _QsLevels = new int[] { int.Parse(rawLevels) };
                }

                return _QsLevels;
            }
        }

        private DateTime QsAfterTimestamp
        {
            get
            {
                string rawDate = Request.QueryString["after"];
                if (!string.IsNullOrEmpty(rawDate))
                {
                    DateTime outDate;
                    if (DateTime.TryParse(rawDate, out outDate))
                        return outDate;
                }

                return DateTime.MinValue;
            }
        }

        private DateTime QsBeforeTimestamp
        {
            get
            {
                string rawDate = Request.QueryString["before"];
                if (!string.IsNullOrEmpty(rawDate))
                {
                    DateTime outDate;
                    if (DateTime.TryParse(rawDate, out outDate))
                        return outDate;
                }

                return DateTime.MaxValue;
            }
        }

        private int QsPageSkip
        {
            get
            {
                string rawIndex = Request.QueryString["skip"];
                int outIndex;
                if (!string.IsNullOrEmpty(rawIndex) && int.TryParse(rawIndex, out outIndex))
                    return outIndex;
                return 0;
            }
        }

        private int QsPageSize
        {
            get
            {
                string rawIndex = Request.QueryString["take"];
                int outIndex;
                if (!string.IsNullOrEmpty(rawIndex) && int.TryParse(rawIndex, out outIndex))
                    return outIndex;
                return 25;
            }
        }

        public EventLog()
            : base("EventLog.ascx")
        {
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            uiBtnFind.Click += (s, a) => Response.Redirect(BuildUrl(0));

            if (!IsPostBack)
                InitForm();

            PopulateLogs();
        }

        private string BuildUrl(int skip)
        {
            return string.Format(
                Request.Url.AbsolutePath + "?log={0}&source={1}&levels={2}&after={3}&before={4}&skip={5}&take={6}",
                HttpUtility.UrlEncode(uiDdlEventLog.SelectedItem.Value),
                HttpUtility.UrlEncode(uiTxtSource.Text),
                string.Join(",", uiCbxLevel.Items.Cast<ListItem>().Where(l => l.Selected).Select(l => l.Value)),
                HttpUtility.UrlEncode(uiTxtAfterDate.Text),
                HttpUtility.UrlEncode(uiTxtBeforeDate.Text),
                skip,
                QsPageSize
            );
        }

        private void InitForm()
        {
            if (!WcfEndpointHelper<WcfConfigurationSettings, ExceptionHandlerType>.IsEndpointOnline())
            {
                uiBtnFind.Enabled = false;
                return;
            }

            uiDdlEventLog.Items.Clear();
            uiDdlEventLog.Items.Add(new ListItem());
            uiDdlEventLog.Items.Add(new ListItem(WcfEndpointHelper<WcfConfigurationSettings, ExceptionHandlerType>.GetCustomEventLogName()));
            uiDdlEventLog.Items.Add(new ListItem("Application"));
            uiDdlEventLog.Items.Add(new ListItem("System"));

            foreach (ListItem item in uiDdlEventLog.Items)
                if (item.Text == QsEventLogName)
                    item.Selected = true;

            uiTxtSource.Text = QsSource;

            if (QsLevels != null)
                foreach (ListItem item in uiCbxLevel.Items)
                    item.Selected = QsLevels.Contains(int.Parse(item.Value));

            uiTxtAfterDate.Text = QsAfterTimestamp != DateTime.MinValue ? QsAfterTimestamp.ToString("yyyy-MM-dd HH:mm:ss") : "";
            uiTxtBeforeDate.Text = QsBeforeTimestamp != DateTime.MaxValue ? QsBeforeTimestamp.ToString("yyyy-MM-dd HH:mm:ss") : "";
        }

        private void PopulateLogs()
        {
            uiDivPaging.Visible = false;

            if (string.IsNullOrEmpty(QsEventLogName) || QsLevels == null || QsPageSize <= 0)
                return;

            SerializableEventRecord[] events = WcfEndpointHelper<WcfConfigurationSettings, ExceptionHandlerType>.ReadFromEventLog(
                QsEventLogName,
                QsLevels.Select(l => (InternalEnums.EventLogLevel)l).ToArray(),
                QsSource,
                QsAfterTimestamp, 
                QsBeforeTimestamp,
                QsPageSkip,
                QsPageSize);

            if (events == null || !events.Any())
                return;

            uiRptEvents.DataSource = events;
            uiRptEvents.DataBind();

            Literal uiLitLevelIcon, uiLitLevel, uiLitDate, uiLitSource, uiLitId;
            TextBox uiTxtEventDetails;
            SerializableEventRecord eventRecord;

            foreach (RepeaterItem item in uiRptEvents.Items)
            {
                uiLitLevelIcon = item.FindControl("uiLitLevelIcon") as Literal;
                uiLitLevel = item.FindControl("uiLitLevel") as Literal;
                uiLitDate = item.FindControl("uiLitDate") as Literal;
                uiLitSource = item.FindControl("uiLitSource") as Literal;
                uiLitId = item.FindControl("uiLitId") as Literal;
                uiTxtEventDetails = item.FindControl("uiTxtEventDetails") as TextBox;
                eventRecord = events[item.ItemIndex];

                uiLitLevelIcon.Text = string.Format(uiLitLevelIcon.Text, Page.ClientScript.GetWebResourceUrl(this.GetType(), "Niknak.Services.TaskScheduler.UI.WebControls.Assets.icon_" + eventRecord.LevelDisplayName + ".png"));
                uiLitLevel.Text = eventRecord.LevelDisplayName;
                uiLitDate.Text = eventRecord.TimeCreated.HasValue ? eventRecord.TimeCreated.Value.ToString("yyyy-MM-dd HH:mm:ss") : "n/a";
                uiLitSource.Text = eventRecord.ProviderName;
                uiLitId.Text = eventRecord.Id.ToString();
                uiTxtEventDetails.Text = eventRecord.Description;
            }

            //paging
            uiDivPaging.Visible = true;

            if (QsPageSkip > 0)
            {
                uiLitPrevPage.Text = string.Format(uiLitPrevPage.Text, BuildUrl(QsPageSkip - QsPageSize));
                uiLitPrevPage.Visible = true;
            }
            if (events.Count() == QsPageSize)
            {
                uiLitNextPage.Text = string.Format(uiLitNextPage.Text, BuildUrl(QsPageSkip + QsPageSize));
                uiLitNextPage.Visible = true;
            }
        }
    }
}
